#ifndef __NET_EVENTLOOP__
#define __NET_EVENTLOOP__

#include<iostream>
#include<vector>
#include<mutex>
#include<functional>
#include<memory>
#include<thread>

#include<stdlib.h>
#include<unistd.h>
#include<sys/eventfd.h>

#include"channel.hpp"
#include"epoll.hpp"

class Eventloop
{
public:
    using Task=std::function<void()>;
    // using EpollPtr=std::shared_ptr<Epoll>;
public:
    Eventloop()
        :_eventloop_epoll(std::make_shared<Epoll>())
    {
        //创建eventfd对象  EFD_CLOEXEC：fork子进程时不继承 EFD_NONBLOCK：读操作不阻塞
        _eventloop_fd=eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC);
        if(_eventloop_fd<0)
        {
            ERR("create event_fd failed!");
            exit(1);
        }
        INF("create eventloop, event_fd is %d",_eventloop_fd);
        
        //设置event的可读回调
        _eventloop_channel=std::make_unique<Channel>(this,_eventloop_fd);
        _eventloop_channel->set_callback(std::bind(&Eventloop::read_eventfd,this),Channel::Read);
        _eventloop_channel->set_events(Channel::Be_Read);
    }

    //开始事件循环    
    void start()
    {
        while(1)
        {
            //开始epoll监听
            _eventloop_epoll->poll();

            run_all_task();
        }
    }

    //执行任务池中所有任务
    void run_all_task()
    {
        std::vector<Task> task;
        _eventlopp_is_task_dealing=true;
        {
            std::unique_lock<std::mutex> mtx(_eventloop_mutex);
            _eventloop_tasks.swap(task);
        }
        for(auto& func:task)
        {
            func();
        }
        _eventlopp_is_task_dealing=false;
    }

    //加入任务到循环，若任务处于当前线程，则执行；若不在，加入任务池
    void add_task(const Task& cb)
    {
        INF("eventloop add one task");
        //eventloop由独立的线程来顺序执行任务队列
        //这样判断，确保只有eventloop线程能够执行任务，其他线程需要向任务队列提交任务
        if(is_in_loop())
        {
            cb();
        }
        else
        {
            {
            std::unique_lock<std::mutex> mtx(_eventloop_mutex);
            _eventloop_tasks.emplace_back(cb);
            }
            //加入任务池之后，唤醒事件循环，若任务池正在处理中，则无需唤醒
            if(!_eventlopp_is_task_dealing)weak_eventfd();
        }
    }

    //判断当前线程是否是eventLoop对应的线程
    bool is_in_loop()
    {
        return (_eventloop_thread_id==std::this_thread::get_id());
    }

    //当事件循环被唤醒后，必须调用此函数读取eventfd的数据，重置其状态
    //读取操作会清零eventfd的内部计数器，避免事件循环持续被触发
    void read_eventfd()
    {
        uint64_t res=1;
        int ret=read(_eventloop_fd,&res,sizeof(res));
        if(ret<0)
        {
            //EINTR:被信号打断 EAGAIN:无数据可读
            if(errno==EINTR||errno==EAGAIN)return;
            ERR("read eventfd failed");
            exit(2);
        }
    }

    //当其他线程需要唤醒阻塞在epoll_wait中的事件循环时（例如有新任务加入）
    //向eventfd写入一个64位整数1
    //写入操作会使内核递增eventfd的内部计数器，触发关联的可读事件，导致阻塞在I/O多路复用中的事件循环立即返回
    void weak_eventfd()
    {
        uint64_t res=1;
        int ret=write(_eventloop_fd,&res,sizeof(res));
        if(ret<0)
        {
            if(errno==EINTR)return;
            ERR("read eventfd failed");
            exit(2);
        }
    }

    //调用epoll接口
    void epoll_update(Channel* channel)
    {
        return _eventloop_epoll->epoll_update(channel);
    }
    void epoll_remove(Channel* channel)
    {
        return _eventloop_epoll->epoll_remove(channel);
    }

private:
    int _eventloop_fd;                          //event的fd
    std::thread::id _eventloop_thread_id{std::this_thread::get_id()};
                                                //eventloop所出线程的id
    std::unique_ptr<Channel> _eventloop_channel;//eventfd的channel
    std::shared_ptr<Epoll> _eventloop_epoll;    //监控loop中的sock状态
    std::vector<Task> _eventloop_tasks;         //任务池

    bool _eventloop_is_quit{false};             //eventloop是否退出
    bool _eventlopp_is_task_dealing{false};     //任务池是否在处理任务

    std::mutex _eventloop_mutex;
};

#endif